home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 46 / Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso / -in_the_mag- / reader_requests / amiga-e / examples / subtask.e < prev    next >
Text File  |  1999-09-13  |  22KB  |  713 lines

  1. /*
  2. **  Original C Code written by Stefan Stuntz
  3. **
  4. **  Translation into E by Klaus Becker
  5. **
  6. **  All comments are from the C-Source
  7. */
  8.  
  9. /* Remember the following note from Wouter:
  10.    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  11. "[note: v3.1 (v40) of the amiga operating system is known to contain
  12.  a bug in the IEEE code. Be sure to run a SetPatch that fixes this]"
  13. */
  14.  
  15. /*
  16.  
  17. This little demo show how to write classes which need a long
  18. time to render their contents. In this case, we take a little
  19. fractal algorithm as example. The actual calculations are
  20. done in a separate task, the display is updated from time
  21. to time.
  22.  
  23. */
  24.  
  25. OPT PREPROCESS
  26.  
  27. MODULE 'graphics/gfx'
  28. MODULE 'muimaster','libraries/mui','libraries/muip',
  29.        'mui/muicustomclass','amigalib/boopsi',
  30.        'intuition/classes','intuition/classusr',
  31.        'intuition/screens','intuition/intuition',
  32.        'dos/dostags','dos/dosextens','exec/memory','exec/semaphores',
  33.        'graphics/rastport','exec/ports',
  34.        'utility/tagitem','exec/tasks'
  35.  
  36. /* Pixel dimensions of our fractal */
  37.  
  38. CONST FRACTALWIDTH  = 300
  39. CONST FRACTALHEIGHT = 300
  40.  
  41. /* Fractal Description */
  42.  
  43. OBJECT fractaldesc
  44.   left:LONG
  45.   right:LONG
  46.   top:LONG
  47.   bottom:LONG
  48. ENDOBJECT
  49.  
  50.  
  51. #define MaxIterations 60
  52.  
  53. /* Attributes and methods for the custom class */
  54.  
  55. #define MUISERIALNR_STUNTZI 1
  56. #define TAGBASE_STUNTZI (TAG_USER OR (Shl(MUISERIALNR_STUNTZI,16)))
  57.  
  58. #define MUIM_Class4_Update (TAGBASE_STUNTZI OR 1)
  59.  
  60. OBJECT muip_class4_update
  61.   id,percent
  62. ENDOBJECT
  63.  
  64. #define MUIM_Class4_Calc (TAGBASE_STUNTZI OR 2)
  65.  
  66. OBJECT muip_class4_calc
  67.   id
  68.   fd:PTR TO fractaldesc
  69. ENDOBJECT
  70.  
  71. #define MUIA_Class4_Percent (TAGBASE_STUNTZI OR 3)
  72.  
  73. #define STC_START 0
  74. #define STC_STOP  1
  75.  
  76. /* Instance Data for the fractal class */
  77.  
  78. OBJECT data
  79.   sema:ss                 /* data item protection      */
  80.   app                     /* pointer to application    */
  81.   self                    /* pointer to ourselves      */
  82.   subtask:PTR TO subtask  /* our sub task              */
  83.   rp:rastport             /* rastport FOR the sub task */
  84.   udlines:PTR TO CHAR     /* line update flags ARRAY   */
  85. ENDOBJECT
  86.  
  87. /**************************************************************/
  88. /* Functions for easy and secure spawning/killing of subtasks */
  89. /**************************************************************/
  90.  
  91. OBJECT subtaskmsg
  92.    stm_Message:mn
  93.    stm_Command:INT
  94.    stm_Parameter:LONG 
  95.    stm_Result:LONG
  96. ENDOBJECT
  97.  
  98. OBJECT subtask
  99.   st_Task:PTR TO tc      /* sub task pointer */
  100.   st_Port:PTR TO mp      /* allocated by sub task */
  101.   st_Reply:PTR TO mp     /* allocated by main task */
  102.   st_Data:LONG           /* more initial data to pass to the sub task */
  103.   st_Message:subtaskmsg  /* Message buffer */
  104. ENDOBJECT
  105.  
  106. #define STC_STARTUP  -2
  107. #define STC_SHUTDOWN -1
  108.  
  109. PROC sendsubtaskmsg(st:PTR TO subtask,command,params)
  110.   st.st_Message.stm_Message.replyport:= st.st_Reply
  111.   st.st_Message.stm_Message.length   := SIZEOF subtaskmsg
  112.   st.st_Message.stm_Command          := command
  113.   st.st_Message.stm_Parameter        := params
  114.   st.st_Message.stm_Result           := 0
  115.  
  116.   PutMsg(IF command=STC_STARTUP THEN st.st_Task::process.msgport ELSE st.st_Port,st.st_Message)
  117.   WaitPort(st.st_Reply)
  118.   GetMsg(st.st_Reply)
  119. ENDPROC (st.st_Message.stm_Result)
  120.  
  121. PROC spawnsubtask(name,func,data:PTR TO data)
  122.   DEF st=NIL:PTR TO subtask
  123.  
  124.   IF (st:=AllocVec(SIZEOF subtask,MEMF_PUBLIC OR MEMF_CLEAR))
  125.     st.st_Reply:=CreateMsgPort()
  126.     IF (st.st_Reply)
  127.       st.st_Data:=data
  128.       st.st_Task:= CreateNewProc([NP_ENTRY,func, -> = {renderfunc}
  129.                                   NP_NAME,name,
  130.                                   TAG_DONE])
  131.       IF (st.st_Task)
  132.         IF (sendsubtaskmsg(st,STC_STARTUP,st)) THEN RETURN (st)
  133.       ENDIF
  134.       DeleteMsgPort(st.st_Reply)
  135.     ENDIF
  136.     FreeVec(st)
  137.   ENDIF
  138. ENDPROC
  139.  
  140. PROC killsubtask(st:PTR TO subtask)
  141.   sendsubtaskmsg(st,STC_SHUTDOWN,st)
  142.   DeleteMsgPort(st.st_Reply)
  143.   FreeVec(st)
  144. ENDPROC
  145.  
  146. PROC exitsubtask(st:PTR TO subtask,stm:PTR TO subtaskmsg)
  147.   /*
  148.   ** We reply after a Forbid() to make sure we're really gone
  149.   ** when the main task continues.
  150.   */
  151.   IF (st.st_Port) THEN DeleteMsgPort(st.st_Port)
  152.   Forbid()
  153.   stm.stm_Result:= FALSE
  154.   ReplyMsg(stm)
  155. ENDPROC
  156.  
  157. PROC initsubtask()
  158.   DEF me=NIL:PTR TO tc,
  159.       st=NIL:PTR TO subtask,
  160.       stm=NIL:PTR TO subtaskmsg
  161.  
  162.   me:= FindTask(NIL)
  163.  
  164.   /*
  165.   ** Wait for our startup message from the SpawnSubTask() function.
  166.   */
  167.  
  168.   WaitPort(me::process.msgport)
  169.   stm:= GetMsg(me::process.msgport)
  170.   st:= stm.stm_Parameter
  171.   st.st_Port:=CreateMsgPort()
  172.   IF (st.st_Port)
  173.     /*
  174.     ** Reply startup message, everything ok.
  175.     ** Note that if the initialization fails, the code falls
  176.     ** through and replies the startup message with a stm_Result
  177.     ** of 0 after a Forbid(). This tells SpawnSubTask() that the
  178.     ** sub task failed to run.
  179.     */
  180.     stm.stm_Result:= TRUE
  181.     ReplyMsg(stm)
  182.     RETURN (st)
  183.   ELSE
  184.     exitsubtask(st,stm)
  185.     RETURN (NIL)
  186.   ENDIF
  187. ENDPROC
  188.  
  189. /*******************************************************/
  190. /* Subtask which does all the time-consuming rendering */
  191. /*******************************************************/
  192.  
  193. PROC renderfunc()
  194.   DEF st=NIL:PTR TO subtask
  195.   DEF data=NIL:PTR TO data
  196.   DEF running=TRUE,worktodo=FALSE,x,y
  197.   DEF stm=NIL:PTR TO subtaskmsg
  198.   DEF left,top,right,bottom
  199.   DEF zr,zi,cr,ci,rr,ii
  200.   DEF counter
  201.   DEF command,i
  202.   DEF float[20]:STRING
  203.  
  204.   geta4() -> !!!
  205.  
  206.     IF (st:= initsubtask())
  207.       data:= st.st_Data
  208.       LOOP
  209.         /*
  210.         ** after the sub task is up and running, we go into
  211.         ** a loop and process the messages from the main task.
  212.         */
  213.         WHILE (stm:= GetMsg(st.st_Port))
  214.           command:=stm.stm_Command
  215.           SELECT command
  216.             CASE STC_SHUTDOWN
  217.               /*
  218.               ** This is the shutdown message from KillSubTask().
  219.               */
  220.               running:= FALSE
  221.             CASE STC_START
  222.               /*
  223.               ** we received a start message with a fractal description.
  224.               ** clear the rastport and the line update array and start
  225.               ** rendering.
  226.               */
  227.               SetRast(data.rp,1)
  228.               FOR i:=0 TO FRACTALHEIGHT-1 DO data.udlines[i]:=0
  229.               left   := stm.stm_Parameter::fractaldesc.left
  230.               top    := stm.stm_Parameter::fractaldesc.top
  231.               right  := stm.stm_Parameter::fractaldesc.right
  232.               bottom := stm.stm_Parameter::fractaldesc.bottom
  233.               y:=0
  234.               worktodo:= TRUE
  235.             CASE STC_STOP
  236.               /* this message is not used in this example */
  237.               worktodo:= FALSE
  238.           ENDSELECT
  239.           /*
  240.           ** If we received a shutdown message, we do not reply it
  241.           ** immediately. First, we need to free our resources.
  242.           */
  243.           IF (running=FALSE) THEN BRA exit
  244.           ReplyMsg(stm.stm_Message)
  245.         ENDWHILE
  246.         IF (running=FALSE) THEN BRA exit
  247.         IF (worktodo)
  248.           /* if there is work to do, i.e. if the fractal is not
  249.           ** finished yet, we calculate the next line and draw
  250.           ** it to the offscreen rastport.
  251.           */
  252.           FOR x:=0 TO (FRACTALWIDTH-1)
  253.             zr:= 0.0
  254.             zi:= 0.0
  255.             cr:= !left+(!x*(!right - left)/FRACTALWIDTH )
  256.             ci:= !top+ (!y*(!bottom - top)/FRACTALHEIGHT )
  257.             rr:= !zr*zr
  258.             ii:= !zi*zi
  259.             FOR counter:=0 TO MaxIterations-1
  260.               zi:=!ci + (!zr*zi*2.0)
  261.               zr:=!cr + rr - ii
  262.               rr:=!zr*zr
  263.               ii:=!zi*zi
  264.               IF (!rr+ii>4.0)
  265.                 /*
  266.                 ** set the pixel in the offscreen rastport.
  267.                 ** this demo is kind of dirty, as it does no
  268.                 ** nice color allocation and palette stuff.
  269.                 ** dont be so dirty in your own programs! :-)
  270.                 */
  271.                 SetAPen(data.rp,1+counter)
  272.                 WritePixel(data.rp,x,y)
  273.                 BRA next
  274.               ENDIF
  275.               INC counter
  276.               EXIT (counter=MaxIterations)
  277.             ENDFOR
  278. next:
  279.           ENDFOR
  280.           /*
  281.           ** after the line is finished, we set the corresponding
  282.           ** flag in the line update array to FALSE. This shows the
  283.           ** main task that this line needs to be redrawn the next
  284.           ** time it gets the chance.
  285.           */
  286.  
  287.           ObtainSemaphore(data.sema)
  288.           data.udlines[y]:= FALSE
  289.           IF (data.app)
  290.             /*
  291.             ** if our class is attached to an application, we send ourselves
  292.             ** an update method. Note that because we are in a separate task,
  293.             ** we cannot send this method directly but instead have to use
  294.             ** the MUIM_Application_PushMethod call. This is the only method
  295.             ** that you may send to a MUI object from a separate task. What it
  296.             ** does is to copy the method to a private buffer and wait until
  297.             ** the next time the main task calls the input method. Then, our
  298.             ** update method will be executed under the main tasks context.
  299.             **
  300.             ** If our class is not attached to an application
  301.             ** (i.e. we are outside of MUIM_Setup/MUIM_Cleanup), there is
  302.             ** nobody who could render something anyway so we just skip
  303.             ** the update method and continue to render in our private
  304.             ** buffer.
  305.             */
  306.             -> Gauge
  307.             doMethodA(data.app,[ MUIM_Application_PushMethod,
  308.                   data.self,2,MUIM_Class4_Update,(100*(y+1)/FRACTALHEIGHT)])
  309.           ENDIF
  310.           ReleaseSemaphore(data.sema)
  311.           y++
  312.           IF (y=FRACTALHEIGHT)
  313.             /* check if we are finished to draw our fractal */
  314.             worktodo:= FALSE
  315.           ENDIF
  316.           /* Since we are very busy working, we do not Wait() for signals. */
  317.         ELSE
  318.           /* We have nothing to do, just sit quietly and wait for something to happen */
  319.           WaitPort(st.st_Port)
  320.         ENDIF
  321.       ENDLOOP
  322. exit:
  323.       exitsubtask(st,stm)
  324.     ENDIF
  325. ENDPROC
  326.  
  327. PROC mNew(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
  328.   DEF data=NIL:PTR TO data
  329.  
  330.   IF (obj:=doSuperMethodA(cl,obj,msg))=NIL THEN RETURN 0
  331.  
  332.   data:= INST_DATA(cl,obj)
  333.  
  334.   /* store a pointer to ourselves so the subtask knows about us */
  335.   data.self:= obj
  336.  
  337.   /*
  338.   ** initialization and allocation of data structures.
  339.   ** note that if something fails here, we *must* do a
  340.   ** CoerceMethod(cl,obj,OM_DISPOSE) to give ourselves
  341.   ** (and MUI!) a chance to clean up.
  342.   */
  343.  
  344.   InitSemaphore(data.sema)
  345.   InitRastPort(data.rp)
  346.  
  347.   data.udlines:= AllocVec(FRACTALHEIGHT,MEMF_CLEAR)
  348.   IF (data.udlines)
  349.     data.rp.bitmap:= AllocBitMap(FRACTALWIDTH,FRACTALHEIGHT,8,BMF_CLEAR,NIL)
  350.     IF (data.rp.bitmap)
  351.       SetRast(data.rp,1)
  352.  
  353.       /* the following call starts the sub task */
  354.  
  355.       data.subtask:= spawnsubtask('Class4-Render-Task',{renderfunc},data)
  356.       IF (data.subtask)
  357.         SetTaskPri(data.subtask.st_Task,-1)
  358.         RETURN obj
  359.       ENDIF
  360.     ENDIF
  361.   ENDIF
  362.   coerceMethodA(cl,obj,OM_DISPOSE)
  363. ENDPROC
  364.  
  365. PROC mDispose(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO msg)
  366.   DEF data:PTR TO data
  367.   data:=INST_DATA(cl,obj)
  368.   IF (data.subtask) THEN killsubtask(data.subtask)
  369.   IF (data.rp.bitmap) THEN FreeBitMap(data.rp.bitmap)
  370.   IF (data.udlines) THEN FreeVec(data.udlines)
  371. ENDPROC doSuperMethodA(cl,obj,msg)
  372.  
  373. /*
  374. ** AskMinMax method will be called before the window is opened
  375. ** and before layout takes place. We need to tell MUI the
  376. ** minimum, maximum and default size of our object.
  377. */
  378.  
  379. PROC mAskMinMax(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_askminmax)
  380.   /*
  381.   ** let our superclass first fill in what it thinks about sizes.
  382.   ** this will e.g. add the size of frame and inner spacing.
  383.   */
  384.  
  385.   doSuperMethodA(cl,obj,msg)
  386.  
  387.   /*
  388.   ** now add the values specific to our object. note that we
  389.   ** indeed need to *add* these values, not just set them!
  390.   */
  391.  
  392.   msg.minmaxinfo.minwidth:=msg.minmaxinfo.minwidth+10
  393.   msg.minmaxinfo.defwidth:=msg.minmaxinfo.defwidth+100
  394.   msg.minmaxinfo.maxwidth:=msg.minmaxinfo.maxwidth+FRACTALWIDTH
  395.   
  396.   msg.minmaxinfo.minheight:=msg.minmaxinfo.minheight+10
  397.   msg.minmaxinfo.defheight:=msg.minmaxinfo.defheight+100
  398.   msg.minmaxinfo.maxheight:=msg.minmaxinfo.maxheight+FRACTALHEIGHT
  399. ENDPROC
  400.  
  401. /*
  402. ** Draw method is called whenever MUI feels we should render
  403. ** our object. This usually happens after layout is finished
  404. ** or when we need to refresh in a simplerefresh window.
  405. ** Note: You may only render within the rectangle
  406. **       _mleft(obj), _mtop(obj), _mwidth(obj), _mheight(obj).
  407. */
  408.  
  409. PROC mDraw(cl:PTR TO iclass,obj:PTR TO object,msg:PTR TO muip_draw)
  410.   DEF data:PTR TO data
  411.   DEF l
  412.  
  413.   data:=INST_DATA(cl,obj)
  414.  
  415.   /*
  416.   ** let our superclass draw itself first, area class would
  417.   ** e.g. draw the frame and clear the whole region. What
  418.   ** it does exactly depends on msg.flags.
  419.   **
  420.   ** Note: You *must* call the super method prior to do
  421.   ** anything else, otherwise msg.flags will not be set
  422.   ** properly !!!
  423.   */
  424.  
  425.   doSuperMethodA(cl,obj,msg)
  426.  
  427.   IF (msg.flags AND MADF_DRAWUPDATE)
  428.     /*
  429.     ** This flag indicates that we were called from our
  430.     ** update method. We needn't render the complete
  431.     ** image, we only need to update the lines that
  432.     ** were changed. So what we do is to browse through
  433.     ** the line flag array and blit each changed line
  434.     ** from the offscreen buffer into the display.
  435.     ** We could do a better and more efficient job
  436.     ** by collecting subsequent changed lines to blit
  437.     ** larger rectangles, but hey... this is only a demo! :-)
  438.     */
  439.  
  440.     /*
  441.     ** note the usage of semaphores to protect access
  442.     ** to variables use by both tasks.
  443.     */
  444.  
  445.     ObtainSemaphore(data.sema)
  446.     FOR l:=0 TO _mheight(obj)-1
  447.       IF (data.udlines[l])=NIL
  448.         /*
  449.         ** once we copied the line, we set the corresponding line flag
  450.         ** to indicate that this line is uptodate and does not need
  451.         ** to be redrawn the next time. When our sub task gets the message
  452.         ** to calculate a new fractal, it will reset the flag to FALSE again.
  453.         */
  454.  
  455.         BltBitMapRastPort(data.rp.bitmap,0,l,_rp(obj),_mleft(obj),_mtop(obj)+l,_mwidth(obj),1,$c0)
  456.         data.udlines[l]:= TRUE
  457.       ENDIF
  458.     ENDFOR    
  459.     ReleaseSemaphore(data.sema)
  460.   ELSEIF (msg.flags AND MADF_DRAWOBJECT)
  461.     /*
  462.     ** we were called directly from MUI because the window needs refresh.
  463.     ** no need to care about our line array here, we just copy the complete
  464.     ** offscreen buffer to our display.
  465.     */
  466.     ObtainSemaphore(data.sema)
  467.     BltBitMapRastPort(data.rp.bitmap,0,0,_rp(obj),_mleft(obj),_mtop(obj),_mwidth(obj),_mheight(obj),$c0)
  468.     ReleaseSemaphore(data.sema)
  469.   ENDIF
  470. ENDPROC
  471.  
  472. PROC mSetup(cl:PTR TO iclass,obj,msg:PTR TO muip_handleinput)
  473.   DEF data:PTR TO data
  474.   DEF app
  475.   data:=INST_DATA(cl,obj)
  476.   IF (doSuperMethodA(cl,obj,msg))=NIL THEN RETURN FALSE
  477.  
  478.   /*
  479.   ** set a pointer to our application in our instance data.
  480.   ** this indicates the sub task that we should be notified
  481.   ** when a new line is calculated.
  482.   */
  483.  
  484.   ObtainSemaphore(data.sema)
  485.   get(obj,MUIA_ApplicationObject,{app})
  486.   data.app:=app
  487.   ReleaseSemaphore(data.sema)
  488. ENDPROC TRUE
  489.  
  490. PROC mCleanup(cl:PTR TO iclass,obj,msg:PTR TO muip_handleinput)
  491.   DEF data:PTR TO data
  492.   data:=INST_DATA(cl,obj)
  493.   ObtainSemaphore(data.sema)
  494.   data.app:=NIL
  495.   ReleaseSemaphore(data.sema)
  496. ENDPROC doSuperMethodA(cl,obj,msg)
  497.  
  498. /*
  499. ** a simple method that sends a START msg with
  500. ** fractal description packet to the sub task.
  501. */
  502.  
  503. PROC mCalc(cl:PTR TO iclass,obj,msg:PTR TO muip_class4_calc)
  504.   DEF data:PTR TO data
  505.   data:=INST_DATA(cl,obj)
  506.   sendsubtaskmsg(data.subtask,STC_START,msg.fd)
  507. ENDPROC
  508.  
  509. /*
  510. ** thats the method that is called through MUIM_Application_PushMethod
  511. ** from the subtask.
  512. */
  513.  
  514. PROC mUpdate(cl:PTR TO iclass,obj,msg:PTR TO muip_class4_update)
  515.  
  516.   /* Tell MUI to redraw our object. Set the update flag
  517.   ** so we know that only the changed lines are subject
  518.   ** to render.
  519.   */
  520.  
  521.   Mui_Redraw(obj,MADF_DRAWUPDATE)
  522.  
  523.   /*
  524.   ** Also the the percentage attribute. The class itself doesnt
  525.   ** have any use for this, but if we set it, its possible
  526.   ** for other objects (e.g. a gauge) to receive notifications
  527.   */
  528.  
  529.   set(obj,MUIA_Class4_Percent,msg.percent)
  530.  
  531. ENDPROC
  532.  
  533. /*
  534. ** Here comes the dispatcher for our custom class.
  535. ** Unknown/unused methods are passed to the superclass immediately.
  536. */
  537.  
  538. PROC mydispatcher(cl:PTR TO iclass,obj,msg:PTR TO msg)
  539.   DEF methodid
  540.   methodid:=msg.methodid
  541.  
  542.   SELECT methodid
  543.     CASE OM_NEW             ; RETURN mNew      (cl,obj,msg)
  544.     CASE OM_DISPOSE         ; RETURN mDispose  (cl,obj,msg)
  545.     CASE MUIM_AskMinMax     ; RETURN mAskMinMax(cl,obj,msg)
  546.     CASE MUIM_Draw          ; RETURN mDraw     (cl,obj,msg)
  547.     CASE MUIM_Setup         ; RETURN mSetup    (cl,obj,msg)
  548.     CASE MUIM_Cleanup       ; RETURN mCleanup  (cl,obj,msg)
  549.     CASE MUIM_Class4_Update ; RETURN mUpdate   (cl,obj,msg)
  550.     CASE MUIM_Class4_Calc   ; RETURN mCalc     (cl,obj,msg)
  551.   ENDSELECT
  552.  
  553. ENDPROC doSuperMethodA(cl,obj,msg)
  554.  
  555. /****************************************************************************/
  556. /* Misc Help Functions                                                      */
  557. /****************************************************************************/
  558.  
  559. PROC xget(obj,attribute)
  560.   DEF x
  561.   get(obj,attribute,{x})
  562. ENDPROC x
  563.  
  564. PROC getstr(obj) IS xget(obj,MUIA_String_Contents)
  565.  
  566. /***************************************************************************/
  567. /* Thats all there is about it. Now lets see how things are used...        */
  568. /***************************************************************************/
  569.  
  570. PROC main() HANDLE
  571.   DEF app,window,myObj
  572.   DEF strleft,strtop,strright,strbottom,start,gauge
  573.   DEF mcc=NIL:PTR TO mui_customclass
  574.   DEF signals,running=TRUE,result
  575.   DEF fd:fractaldesc
  576.    
  577.   storea4() -> save A4 !!!
  578.  
  579.   IF (KickVersion(39)=FALSE) THEN
  580.     Raise('runs only with V39 and up')
  581.   IF (muimasterbase:=OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN))=NIL THEN
  582.     Raise('Failed to open muimasterlibrary')
  583.  
  584.   /* Create the new custom class with a call to eMui_CreateCustomClass(). */
  585.   /* Caution: This function returns not a struct IClass, but a            */
  586.   /* struct MUI_CustomClass which contains a struct IClass to be          */
  587.   /* used with NewObjectA() calls.                                         */
  588.   /* Note well: MUI creates the dispatcher hook for you, you may          */
  589.   /* *not* use its h_Data field! If you need custom data, use the         */
  590.   /* cl_UserData of the IClass structure!                                 */
  591.  
  592.   IF (mcc:= eMui_CreateCustomClass(NIL,MUIC_Area,NIL,SIZEOF data,{mydispatcher}))=NIL THEN
  593.     Raise('Could not create custom class.')
  594.  
  595.   app:= ApplicationObject,
  596.     MUIA_Application_Title      , 'Class4',
  597.     MUIA_Application_Version    , '$VER: Class4 12.10 (21.11.95)',
  598.     MUIA_Application_Copyright  , 'c1993, Stefan Stuntz',
  599.     MUIA_Application_Author     , 'Stefan Stuntz & Klaus Becker',
  600.     MUIA_Application_Description, 'Demonstrate rendering from sub tasks.',
  601.     MUIA_Application_Base       , 'Class4',
  602.     SubWindow, window:= WindowObject,
  603.       MUIA_Window_Title, 'Subtask rendering',
  604.       MUIA_Window_ID   , "CLS4",
  605.       WindowContents, VGroup,
  606.         Child, HGroup, GroupSpacing(8),
  607.           Child, ColGroup(2),
  608.             Child, Label2('_Left:'  ), Child, strleft   := Mui_MakeObjectA(MUIO_String,['_L',30]),
  609.             Child, Label2('_Right:' ), Child, strright  := Mui_MakeObjectA(MUIO_String,['_R',30]),
  610.           End,
  611.           Child, ColGroup(2),
  612.             Child, Label2('_Top:'   ), Child, strtop    := Mui_MakeObjectA(MUIO_String,['_T',30]),
  613.             Child, Label2('_Bottom:'), Child, strbottom := Mui_MakeObjectA(MUIO_String,['_B',30]),
  614.           End,
  615.           Child, Mui_MakeObjectA(MUIO_VBar,[2]),
  616.           Child, start := VGroup,
  617.             GroupSpacing(0),
  618.             MUIA_Weight, 0,
  619.             ButtonFrame,
  620.             MUIA_InputMode , MUIV_InputMode_RelVerify,
  621.             MUIA_Background, MUII_ButtonBack,
  622.             Child, VSpace(0),
  623.             Child, TextObject, MUIA_Text_Contents, '\ec  Start  ', End,
  624.             Child, VSpace(0),
  625.           End,
  626.         End,
  627.         Child, gauge := GaugeObject,
  628.           GaugeFrame,
  629.           MUIA_Gauge_Horiz, MUI_TRUE,
  630.           MUIA_Gauge_Max, 100,
  631.           MUIA_FixHeight, 8,
  632.         End,
  633.         Child, myObj := NewObjectA(mcc.mcc_class,NIL,
  634.           [TextFrame,
  635.           MUIA_Background, MUII_BACKGROUND,
  636.           TAG_DONE]),
  637.       End,
  638.     End,
  639.   End
  640.  
  641.   IF (app=NIL) THEN Raise('Failed to create Application.')
  642.  
  643.   set(window,MUIA_Window_DefaultObject, myObj)
  644.  
  645.   doMethodA(window,[MUIM_Notify,MUIA_Window_CloseRequest,MUI_TRUE,
  646.     app,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit])
  647.  
  648.   doMethodA(start,[MUIM_Notify,MUIA_Pressed,FALSE,
  649.     app,2,MUIM_Application_ReturnID,1])
  650.  
  651.   doMethodA(myObj,[MUIM_Notify,MUIA_Class4_Percent,MUIV_EveryTime,
  652.     gauge,3,MUIM_Set,MUIA_Gauge_Current,MUIV_TriggerValue])
  653.  
  654.   set(strleft  ,MUIA_String_Contents,'-2.0')
  655.   set(strright ,MUIA_String_Contents,'1.0')
  656.   set(strtop   ,MUIA_String_Contents,'1.5')
  657.   set(strbottom,MUIA_String_Contents,'-1.5')
  658.  
  659. /*
  660. ** Input loop...
  661. */
  662.  
  663.   set(window,MUIA_Window_Open,MUI_TRUE)
  664.  
  665.   WHILE running
  666.     result:=doMethodA(app,[MUIM_Application_Input,{signals}])
  667.     SELECT result
  668.       CASE MUIV_Application_ReturnID_Quit
  669.         running:= FALSE
  670.       CASE 1  -> Start-Button
  671.         fd.left   := RealVal(getstr(strleft  ))
  672.         fd.right  := RealVal(getstr(strright ))
  673.         fd.top    := RealVal(getstr(strtop   ))
  674.         fd.bottom := RealVal(getstr(strbottom))
  675.         IF ( (fd.right > fd.left) AND (fd.top > fd.bottom) )
  676.           doMethodA(myObj,[MUIM_Class4_Calc,fd])
  677.         ELSE
  678.           DisplayBeep(0)
  679.         ENDIF
  680.     ENDSELECT
  681.      
  682.     IF (running AND signals) THEN Wait(signals)
  683.    ENDWHILE
  684.    set(window,MUIA_Window_Open,FALSE)
  685.  
  686. /*
  687. ** Shut down...
  688. */
  689. EXCEPT DO
  690.   IF app THEN Mui_DisposeObject(app)     /* dispose all objects. */
  691.   IF mcc THEN Mui_DeleteCustomClass(mcc) /* delete the custom class. */
  692.   IF muimasterbase THEN CloseLibrary(muimasterbase)
  693.   IF exception THEN WriteF('\s\n',exception)
  694. ENDPROC
  695.  
  696. -> geta4.e - store and get the global data pointer kept in register A4
  697. -> (C) Leon Woestenberg
  698.  
  699. PROC storea4()
  700.   LEA a4storage(PC),A0
  701.   MOVE.L A4,(A0)
  702. ENDPROC
  703.  
  704. PROC geta4()
  705.   LEA a4storage(PC),A0
  706.   MOVE.L (A0),A4
  707. ENDPROC
  708.  
  709. a4storage:
  710.   LONG NIL
  711.  
  712.  
  713.